package handler

import (
	"fmt"
	"go-devops/common"
	"go-devops/domain/dto"
	"go-devops/domain/model"
	"log"
	"os/exec"
	"time"
)

type CommonTaskHandler struct {
}

func NewCommonTaskHandler() *CommonTaskHandler {
	return &CommonTaskHandler{}
}

func GetSecret(secretType string, name string) (*model.Secret, error) {
	secret, err := model.QuerySecretByNameAndType(secretType, name)
	if err != nil {
		return nil, fmt.Errorf("密钥获取失败")
	}

	key := common.Config.Node.Secret
	decryptSecretKey, err := common.AesDecrypt(key, secret.SecretKey)
	if err != nil {
		return nil, fmt.Errorf("密钥解密失败")
	}

	decryptSecretValue, err := common.AesDecrypt(key, secret.SecretValue)
	if err != nil {
		return nil, fmt.Errorf("密钥解密失败")
	}

	secret.SecretKey = string(decryptSecretKey)
	secret.SecretValue = string(decryptSecretValue)
	return secret, nil
}

func (c CommonTaskHandler) BeforeHandler(context *dto.NodeContext) error {
	context.DockerId = common.NewUUID()
	taskData := context.TaskData
	taskData.Status = common.RUN
	handleNodeStatus(context, &taskData)
	TaskConnMap.Send(context, model.MsgBuild(common.SUCCESS, true, "开始处理："+taskData.Title))
	return nil
}

func (c CommonTaskHandler) AfterHandler(context *dto.NodeContext) error {
	taskData := context.TaskData
	taskData.Status = common.SUCCESS
	handleNodeStatus(context, &taskData)
	TaskConnMap.Send(context, model.MsgBuild(common.SUCCESS, true, taskData.Title+"执行成功"))
	return nil
}

func (c CommonTaskHandler) Handle(context *dto.NodeContext, doHandle func() error) error {
	taskData := context.TaskData
	log.Printf("CommonTaskHandler taskData:%+v\n", taskData)
	log.Printf("start handle nodeType:%s taskId:%s \n", taskData.TaskType, taskData.Id)

	startTime := time.Now()

	if err := c.BeforeHandler(context); err != nil {
		return err
	}

	if err := doHandle(); err != nil {
		return err
	}

	if err := c.AfterHandler(context); err != nil {
		return err
	}

	endTime := time.Now() // 记录结束时间
	elapsedTime := endTime.Sub(startTime)
	log.Printf("end handle nodeType:%s cost:%s \n", taskData.TaskType, elapsedTime)

	TaskConnMap.Send(context, model.MsgBuild(model.INFO, true, fmt.Sprintf("处理节点：%s 耗时：%s", taskData.Title, elapsedTime)))
	return nil
}

func handleNodeStatus(context *dto.NodeContext, taskData *dto.TaskData) {
	status := &dto.NodeStatusData{
		Id:     taskData.Id,
		Status: taskData.Status,
	}

	data := &model.MsgData{
		MsgType: model.NODE,
		Data:    status,
		Time:    common.NowStr(),
	}
	TaskConnMap.Send(context, data)
}

func sendMsg(context *dto.NodeContext, time bool, msg string) {
	TaskConnMap.Send(context, model.MsgBuild(model.INFO, time, msg))
}

type CustomWriter struct {
	Ctx *dto.NodeContext
}

func (cw *CustomWriter) Write(p []byte) (n int, err error) {
	msg := string(p)
	log.Printf("customWriter:%s", msg)
	sendMsg(cw.Ctx, false, msg)
	return len(p), nil
}

func ExecCmd(nodeContext *dto.NodeContext, command string, dir string, showCmd bool) error {
	log.Println("执行工作目录：" + dir)
	log.Println("执行命令：" + command)
	sendMsg(nodeContext, true, fmt.Sprintf("执行工作目录：%s", dir))
	if showCmd {
		sendMsg(nodeContext, true, fmt.Sprintf("执行命令：%s", command))
	}

	cmd := exec.CommandContext(nodeContext.Context, "/bin/sh", "-c", command)
	cmd.Dir = dir

	customWriter := &CustomWriter{
		Ctx: nodeContext,
	}
	cmd.Stdout = customWriter
	cmd.Stderr = customWriter

	// 启动命令
	sendMsg(nodeContext, true, "开始执行处理：--------------------------------------->")
	startTime := time.Now()
	if err := cmd.Start(); err != nil {
		return fmt.Errorf("failed to start command: %w", err)
	}

	// 等待命令完成
	if err := cmd.Wait(); err != nil {
		log.Printf("failed to wait command: %v\n", err)
		return fmt.Errorf("command finished with error: %w", err)
	}
	endTime := time.Now() // 记录结束时间
	elapsedTime := endTime.Sub(startTime)
	sendMsg(nodeContext, true, "执行处理结束 <--------------------------------------- 耗时："+elapsedTime.String())
	return nil
}
